package com.chalmers.foa.gamemodel.gameobjects.other;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;

import android.graphics.Point;
import android.util.Log;

import com.chalmers.foa.gamehandlers.impl.CollisionHandler;
import com.chalmers.foa.gamehandlers.impl.InputHandler;
import com.chalmers.foa.gamehandlers.impl.PhysicsHandler;
import com.chalmers.foa.gamemodel.gameobjects.DirectionType;
import com.chalmers.foa.gamemodel.gameobjects.IGameObject;
import com.chalmers.foa.gamemodel.gameobjects.effects.ParticleEffect;
import com.chalmers.foa.gamemodel.gameobjects.effects.impl.DismemberEffect;
import com.chalmers.foa.gamemodel.gameobjects.hazards.IHazard;
import com.chalmers.foa.gamemodel.gameobjects.other.impl.Door;
import com.chalmers.foa.gamemodel.gameobjects.other.impl.DoorIntent;
import com.chalmers.foa.gamemodel.gameobjects.other.impl.Enemy;
import com.chalmers.foa.gamemodel.gameobjects.other.impl.Key;
import com.chalmers.foa.gamemodel.gameobjects.other.impl.PlayerObject;
import com.chalmers.foa.gamemodel.gameobjects.switches.ISwitch;
import com.chalmers.foa.util.NewList;

public class PlayerModel {
	public enum State{
		Standing,Walking,Jumping,Dead;
	}
	private final static int JUMP_SPEED = -25;
	private final static int SPEED_X = 10;
	private final static int SPEED_Y = 40;
	private final static Point POINTZERO = new Point(0,0);
	
	private State state=State.Standing;
	private PlayerObject playerObject;
	private Point velocity;
	private Point maxSpeed;
	private int jumpSpeed;
	private Key key;
	private ParticleEffect dismemberEffect;
	private NewList collidingObjects;
	private IGameObject collidingObject;
	private boolean canSwitch,previousSwitched;
	private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
	
	
	public PlayerModel(IGameObject _player) {
		playerObject =(PlayerObject)_player;
		jumpSpeed = JUMP_SPEED;
		velocity = new Point(0,0);
		maxSpeed = new Point(SPEED_X,SPEED_Y);
		dismemberEffect = new DismemberEffect(playerObject.getPosition(), playerObject.getColors());
		collidingObjects = new NewList(10);
		canSwitch=true;
		previousSwitched=false;
	}
	
	public PlayerObject getPlayerObject() {
		return playerObject;
	}
	
	public void restart(){
		key=null;
		playerObject.revertToStartPosition();
		state = State.Standing;
	}
	
	public void setSpeed(int _x,int _y) {
		velocity.x = _x;
		velocity.y = _y;
	}
	public State checkJump(){
		if(velocity.y==0)
			state=State.Standing;
		return state;
	}
	public State getState(){
		return state;
	}
	public Point getSpeed(){
		return velocity;
	}
	public Point getMaxSpeed(){
		return maxSpeed;
	}
	public ParticleEffect getParticleEffect(){
		return dismemberEffect;
	}
	
	public void adjustSpeedToMaxSpeed() {
		if(Math.abs(velocity.x) > maxSpeed.x)
			if(velocity.x > 0)
				velocity.x = maxSpeed.x;
			else velocity.x = -maxSpeed.x;
		if(Math.abs(velocity.y) > maxSpeed.y)
			if(velocity.y > 0)
				velocity.y = maxSpeed.y;
			else velocity.y = -maxSpeed.y;
	}
	
	public void jump(int gravity) {
		if(velocity.y == 0 && playerObject.getPosition().y==playerObject.getPreviousPosition().y&&state!=State.Jumping){
			if(gravity>0)
				velocity.y +=  jumpSpeed*(InputHandler.getInstance().getSpeedMultiplier()-0.1f);//*gravity;
			else
				velocity.y -=  jumpSpeed*(InputHandler.getInstance().getSpeedMultiplier()-0.1f);//*gravity;
			state=State.Jumping;
		}
	}
	
	public void update() {
		PhysicsHandler.getInstance().applyGravitationToOffset(velocity);
		adjustSpeedToMaxSpeed();
		CollisionHandler.getInstance().objectsCollidingWithObject(playerObject, POINTZERO, collidingObjects);
		CollisionHandler.getInstance().validateOffset(playerObject, velocity);
		previousSwitched=false;
		for(int i = 0; i < collidingObjects.getSize(); i++){
			collidingObject = collidingObjects.getObjectAt(i);
			if(playerObject.isAlive() && collidingObject.isAlive()) {
				if(collidingObject instanceof Enemy && collidingObject.isAlive()) {
					if(CollisionHandler.getInstance().objectsAreColliding(
							playerObject, POINTZERO, collidingObject)){
						kill();
						break;
					}
				}
				else if(collidingObject instanceof Key) {
					if(key==null){
						pickedUpKey((Key) collidingObject);
						break;
					}
				}
				else if(collidingObject instanceof Door) {
					if(key != null){
						levelFinished();
						break;
					}
				}
				else if(collidingObject instanceof DoorIntent) {
					pcs.firePropertyChange(new PropertyChangeEvent(this,
							"startIntent", null, ((DoorIntent)collidingObject).getIntent()));
				}
				else if(collidingObject instanceof IHazard) {
					kill();
					break;
				}
				else if(collidingObject instanceof ISwitch) {
					if(canSwitch){
						((ISwitch) collidingObject).setSwitched();
						canSwitch=false;
					}
					previousSwitched=true;
				}
			}
		}
		if(!previousSwitched)
			canSwitch=true;
		if(PhysicsHandler.getInstance().getGravity() > 0) {
			if(playerObject.getGravityDirection() == DirectionType.UP) {
				playerObject.setGravityDirection(DirectionType.DOWN);
				playerObject.setDirectionChanged(true);
				if(playerObject.getBoundObject() instanceof Key){
					playerObject.getBoundObject().setNewPosition(new Point(playerObject.getPosition().x,playerObject.getPosition().y-20));
				}
			}
		}
		else if(PhysicsHandler.getInstance().getGravity() < 0)
			if(playerObject.getGravityDirection() == DirectionType.DOWN) {
				playerObject.setGravityDirection(DirectionType.UP);
				playerObject.setDirectionChanged(true);
				if(playerObject.getBoundObject() instanceof Key){
					playerObject.getBoundObject().setNewPosition(new Point(playerObject.getPosition().x,playerObject.getPosition().y+20));
				}
			}	
		
		if(velocity.x > 0) {
			if(playerObject.getMovingDirection() == DirectionType.LEFT) {
				playerObject.setMovingDirection(DirectionType.RIGHT);
				playerObject.setDirectionChanged(true);
			}
		}
		else if (velocity.x < 0)
			if(playerObject.getMovingDirection() == DirectionType.RIGHT) {
				playerObject.setMovingDirection(DirectionType.LEFT);
				playerObject.setDirectionChanged(true);
			}
		
		playerObject.translate(velocity.x, velocity.y);	
	}
	public void levelFinished(){
		pcs.firePropertyChange(new PropertyChangeEvent(this,
				"levelFinished", null, null));
		
	}
	public void pickedUpKey(Key _key){
		key = _key;
		key.triggerEvent();
		playerObject.bindObject(key,new Point(0,-20)); // Bind the key 10 pixels above the player
	}
	public void kill() {
		playerObject.unbindObject();
		key = null;
		playerObject.setAlive(false);
		pcs.firePropertyChange(new PropertyChangeEvent(this,
				"playerKilled", null, null));
		playerObject.revertToStartPosition();
		state = State.Dead;
	}
	public void addPropertyChangeListener(PropertyChangeListener pcl) {
		pcs.addPropertyChangeListener(pcl);
	}
	
}
